package com.ikingtech.framework.sdk.approve.embedded;

import com.ikingtech.framework.sdk.approve.embedded.annotation.Form;
import com.ikingtech.framework.sdk.approve.embedded.annotation.Widget;
import com.ikingtech.framework.sdk.approve.model.rpc.ApproveFormBeanDefinition;
import com.ikingtech.framework.sdk.approve.model.rpc.ApproveFormWidgetBeanDefinition;
import com.ikingtech.framework.sdk.enums.approve.ApproveFormTypeEnum;
import com.ikingtech.framework.sdk.utils.Tools;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.Ordered;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static com.ikingtech.framework.sdk.context.constant.CommonConstants.APPROVE_FORM_BEAN_DEFINITION_REPORT_RUNNER_ORDER;

/**
 * @author tie yan
 */
@Slf4j
@RequiredArgsConstructor
public class ApproveFormBeanDefinitionFactory implements ApplicationRunner, ApplicationContextAware, Ordered {

    private final ApproveFormBeanDefinitionReporter reporter;

    private ApplicationContext applicationContext;

    protected static final Map<String, ApproveFormBeanDefinition> APPROVE_FORM_BEAN_DEFINITION_MAP = new HashMap<>();

    @Override
    public int getOrder() {
        return APPROVE_FORM_BEAN_DEFINITION_REPORT_RUNNER_ORDER;
    }

    @Override
    public void run(ApplicationArguments args) {
        Map<String, Object> formMap = this.applicationContext.getBeansWithAnnotation(Form.class);
        if (Tools.Coll.isBlankMap(formMap)) {
            return;
        }

        for (Object form : formMap.values()) {
            Class<?> formClass = form.getClass();
            Form formAnnotation = formClass.getAnnotation(Form.class);
            ApproveFormBeanDefinition formBeanDefinition = new ApproveFormBeanDefinition();
            formBeanDefinition.setType(ApproveFormTypeEnum.PROCESS_ONLY);
            formBeanDefinition.setBusinessType(formAnnotation.businessType());
            formBeanDefinition.setName(formAnnotation.name());
            List<ApproveFormWidgetBeanDefinition> widgets = new ArrayList<>();
            while (null != formClass) {
                Field[] declaredFields = formClass.getDeclaredFields();
                for (Field declaredField : declaredFields) {
                    Widget widgetAnnotation = declaredField.getAnnotation(Widget.class);
                    if (null != widgetAnnotation) {
                        ApproveFormWidgetBeanDefinition widgetBeanDefinition = new ApproveFormWidgetBeanDefinition();
                        widgetBeanDefinition.setWidgetName(declaredField.getName());
                        widgetBeanDefinition.setWidgetLabel(widgetAnnotation.label());
                        widgetBeanDefinition.setWidgetType(widgetAnnotation.type());
                        widgetBeanDefinition.setRequired(widgetAnnotation.required());
                        widgets.add(widgetBeanDefinition);
                    }
                }
                formClass = formClass.getSuperclass();
            }
            formBeanDefinition.setWidgets(widgets);
            formBeanDefinition.setVisible(formAnnotation.visible());
            APPROVE_FORM_BEAN_DEFINITION_MAP.put(formAnnotation.businessType(), formBeanDefinition);
        }
        this.reporter.run();
    }

    @Override
    public void setApplicationContext(@NonNull ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}
